/* SAT satisfication
* 1.SAT问题
    给定 n 个变量，每个变量的取值只有两种： {0,1} 。然后给定若干个限制，每个限制的形式为 {xi=0/1}∨{xj=0/1}，
    表示 ”xi为 0/1” 或 ” xj为 0/1” 至少有一项成立。问你对于每个变量是否存在一组取值使得每个限制同时满足

* 2.2-SAT问题
    每个条件包含两个命题的SAT问题
    如：对于x1,x2,x3使得x1∨x3,¬x2∨x3成立

    转化：建图
    用xi表示xi=True，用¬xi表示xi=False用图论里的每一个点表示每一个命题，每一条边表示每两个命题间的推导关系
    推导关系：a→b <-> ¬a∨b a,b∈{True,False} 即：a∨b <-> ¬a→b <-> ¬b→a 那么可以把每一个条件表示为图论中的两条边了

    解的情况
    无解：xi→⋯→xi∧¬xi→…xi即xi和¬xi在同一个强连通分量里，说明xi不管取真或假都是相反的，这就有问题了
    有解：枚举所有xi，缩点找强连通分量，当xi所在的强连通分量的拓扑排序在¬x所在的强连通分量的拓扑排序之后时，取x为true

* 本题:
    对于若干个条件，即如果第 i 场使用 x，则第 j 场应该使用 y，
                    如果第 i 场本身就不能使用 x，则显然该条件没用，可以忽略，
                否则如果第 j 场本身不能使用 y，则应该使条件不成立，即第 i 场不应该使用 x，
                否则如果第 j 场能使用 y 的话，则应该使第 i 场使用 x 这个命题表示的节点指向第 j 场使用 y 这个命题表示的节点，同时逆否命题也需要加入边

    3-SAT -> 2-SAT
    即对于有 x 的场次来说，其一定是选 B 或 C，或者选 A 或 C，
    即其可以等价于两种 2-SAT，共有 2^d 种组合，这样就将问题完全转化为 2-SAT 问题
*/

#define DEBUG
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100010, M=200010, INF=0x3f3f3f3f;

int n, d, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp, stk[N], top;
int scc[N], cnt;
bool instk[N];
/*
    dfn[N]：时间戳数组，dfn[u] 表示节点 u 在深度优先搜索中第一次被访问的时间戳。时间戳从 1 开始递增。
    low[N]：追溯值数组，low[u] 表示节点 u 及其子孙节点能够追溯到的最早的时间戳。
    timestamp：时间戳计数器，初始值为 0，每次访问一个新节点时，timestamp 加 1。
    stk[N]：栈数组，用于存储当前正在访问的节点。在深度优先搜索过程中，将节点依次压入栈中。
    top：栈顶指针，初始值为 0，表示栈为空。
    scc[N]：强连通分量编号数组，scc[u] 表示节点 u 所属的强连通分量的编号。强连通分量的编号从 1 开始递增。
    cnt：强连通分量的数量，初始值为 0。
    instk[N]：标记数组，instk[u] 表示节点 u 是否在栈中。
*/
char s[N]; //每场游戏的地图类型
int pos[10]; //记录x类型地图的位置
struct OP
{
    int x, y; 
    char a, b; //x场使用a y场使用b
}op[M];

void AddEdge(int a, int b)
{
    e[idx]=b, ne[idx]=h[a], h[a]=idx++;
}

void Tarjan(int u)
{
    dfn[u] = low[u] = ++timestamp;
    stk[++top]=u, instk[u]=true;
    for(int i=h[u]; ~i; i=ne[i])
    {
        int v=e[i];
        if(!dfn[v])
        {
            Tarjan(v);
            low[u]=min(low[u], low[v]);
        } 
        else if(instk[v]) low[u]=min(low[u], dfn[v]);
    }

    if(low[u] == dfn[u])
    {
        int v;
        cnt++;
        do
        {
            v=stk[top--], instk[v]=false, scc[v]=cnt;
        } while (v != u);
        
    }
}
/*
编码规则：
地图a（0）: 0:赛车B, 1:赛车A
地图b（1）: 0:赛车A, 1:赛车C
地图c（2）: 0:赛车A, 1:赛车B
*/

int get(int x, char a, int t) //地图x 赛车型号a 状态t(0选择 1不选)->图中的节点编号
{
    a -= 'A';
    char b = s[x] - 'a'; //地图
    if (((b + 1) % 3 == a) ^ t) //当前地图与赛车匹配t(0选择 1不选)
        return x; //地图x选择a，返回点编号x，表示该图的选择为0
    return x+n; //地图x不选择a，返回点编号x+n，表示该图的选择为1
}

char put(int x, int t)//地图x 状态t(1输出图选择0，0输出图选择1)->对应的赛车型号
{
    int y = s[x] - 'a';
    return 'A' + (y + t) % 3;
}

bool work()
{
    memset(h, -1, sizeof h);
    memset(dfn, 0, sizeof dfn);
    idx = timestamp = cnt = 0;

    for(int i=0; i<m; i++) //添加规则边
    {
        int x=op[i].x-1, y=op[i].y-1;
        char a=op[i].a, b=op[i].b;
        if(a+32 != s[x]) //x张图选a赛车
        {
            if(b+32 != s[y]) //y张图选b赛车 前不选后不选 后选前选
                AddEdge(get(x,a,0), get(y,b,0)), AddEdge(get(y,b,1), get(x,a,1));
                //x选择a->y选择b 逆否边y不选择b->x不选择a
            else //后件不匹配->前件也不可匹配
                AddEdge(get(x,a,0), get(x,a,1));
                //y张图不选b赛车，x也可以不选择a x选择a->x不选择a
        }
    }
    
    for(int i=0; i<n<<1; i++)
        if(!dfn[i])
            Tarjan(i);

    for(int i=0; i<n; i++)
        if(scc[i]==scc[i+n]) //每个节点的左右节点如果在同一个连通分量中
            return false;
    for(int i=0; i<n; i++)
        if(scc[i]<scc[i+n]) //输出小的拓扑序
            putchar(put(i, 1)); //第一个选择(选择0)
        else
            putchar(put(i, 2)); //第二个选择(选择1)

    return true;
}

int main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
    #else
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    #endif

    cin >> n >> d; //游戏场次 x类型地图数量
    cin >> s; //地图类型字符串
    cin >> m; //m条用车规则

    for(int i=0, j=0; s[i]; i++)
        if(s[i]=='x')
            pos[j++]=i;
    
    for(int i=0; i<m; i++)
        cin >> op[i].x >> op[i].a >> op[i].y >> op[i].b;

    //枚举每个x取a(B, C)或取b(A, C)的情况
    for(int i=0; i<1<<d; i++) //每个x有2种取值
    {
        for(int j=0; j<d; j++)
            if(i>>j&1) s[pos[j]]='a'; //s取地图a (B,C)
            else s[pos[j]]='b'; //s取地图b (A,C)
        if(work()) return 0;
    }
    puts("-1");
    return 0;
}